#include "Pad.h"

//#include "moc_Pad.cxx"
#include "ui_Pad.h"

#include <QMouseEvent>

double Pad::presetspeeds[] = {1.0, 2.0, 4.0, 8.0, 32.0, 64.0, 128.0, 200.0, 400.0, 800.0 };

//QString *Pad::presetspeedslabels[] = {new QString("1.0x"), new QString("2.0x"), new QString("4.0x"), new QString("8.0x"), new QString("32.0x"), 
//    new QString("64.0x"), new QString("128.0x"), new QString("200.0x"), new QString("400.0x"), new QString("800.0x") };
    
Pad::Pad(INDI::BaseClient *c)
:QObject()
{ 
  client=c;
  ui = new Ui::Pad();
  presetspeedslabels=new QStringList();
  *presetspeedslabels<<"1.0x"<<"2.0x"<<"4.0x"<<"8.0x"<<"32.0x"<<"64.0x"<<"128.0x"<<"200.0x"<<"400.0x"<<"800.0x";
  telescope = 0;
  
}

void Pad::setupUi(QWidget* parent)
{
  ui->setupUi(parent);
  ui->comboBoxspeed->clear();
  ui->comboBoxspeed->addItems(*presetspeedslabels);
  // for (i=0; i < 10; i++) {
  //   ui->comboBoxspeed->addItem(*(presetspeedslabels[i]), QVariant::fromValue<double>(presetspeeds[i]));
  // }
  connect(ui->pushButtonJoystick, SIGNAL(clicked(bool)), this, SLOT(setJoypadActive(bool)));
  
  padbuttonevents.insert(QString("NORTH"), new PadButtonEvent(this, QString("NORTH"), ui->pushButtonN));
  padbuttonevents.insert(QString("SOUTH"), new PadButtonEvent(this, QString("SOUTH"), ui->pushButtonS));
  padbuttonevents.insert(QString("EAST"), new PadButtonEvent(this, QString("EAST"), ui->pushButtonE));
  padbuttonevents.insert(QString("WEST"), new PadButtonEvent(this, QString("WEST"), ui->pushButtonW));
  padbuttonevents.insert(QString("SYNC"), new PadButtonEvent(this, QString("SYNC"), ui->pushButtonsync));
  padbuttonevents.insert(QString("ABORT"), new PadButtonEvent(this, QString("ABORT"), ui->pushButtonabort));
  padbuttonevents.insert(QString("SPEED+"), new PadButtonEvent(this, QString("SPEED+"), &Pad::incspeed));
  padbuttonevents.insert(QString("SPEED-"), new PadButtonEvent(this, QString("SPEED-"), &Pad::decspeed));
}

void Pad::setTelescope(INDI::BaseDevice *basedev )
{
  if (basedev) {
    telescope = static_cast<INDI::Telescope *>(basedev);
    makeConnections();
    return;
  }
  telescope = 0;
}

void Pad::setJoypadActive(bool active)
{
  isJoypadActive = active;
}

bool Pad::getJoypadActive()
{
  return isJoypadActive;
}

void Pad::makeConnections()
{
 dirsignalMapper= new QSignalMapper(this);
 dirsignalMapper->setMapping(ui->pushButtonN, NORTH);
 dirsignalMapper->setMapping(ui->pushButtonS, SOUTH);
 dirsignalMapper->setMapping(ui->pushButtonW, WEST);
 dirsignalMapper->setMapping(ui->pushButtonE, EAST);
 
 connect(ui->pushButtonN, SIGNAL(pressed()), dirsignalMapper, SLOT(map()));
 connect(ui->pushButtonN, SIGNAL(released()), dirsignalMapper, SLOT(map()));
 connect(ui->pushButtonS, SIGNAL(pressed()), dirsignalMapper, SLOT(map()));
 connect(ui->pushButtonS, SIGNAL(released()), dirsignalMapper, SLOT(map())); 
 
 connect(ui->pushButtonW, SIGNAL(pressed()), dirsignalMapper, SLOT(map()));
 connect(ui->pushButtonW, SIGNAL(released()), dirsignalMapper, SLOT(map()));
 connect(ui->pushButtonE, SIGNAL(pressed()), dirsignalMapper, SLOT(map()));
 connect(ui->pushButtonE, SIGNAL(released()), dirsignalMapper, SLOT(map()));

 connect(dirsignalMapper, SIGNAL(mapped(int)), this, SLOT(pressdirection(int)));
 
 connect(ui->comboBoxspeed, SIGNAL(activated(int)), this, SLOT(changespeed(int)));
 connect(ui->comboBoxspeed, SIGNAL(editTextChanged(QString)), this, SLOT(changespeed(QString)));
 connect(ui->pushButtonabort, SIGNAL(clicked(bool)), this, SLOT(abortmotion()));
 
 connect(ui->pushButtonsync, SIGNAL(clicked(bool)), this, SLOT(syncLast()));
 
}

/* slots for INDI actions */
void Pad::pressdirection(int d)
{
  ISwitchVectorProperty *switchprop=NULL;
  ISwitch *switchdir=NULL;
  
  if ((d == NORTH) || (d==SOUTH)) {
    switchprop=telescope->getSwitch("TELESCOPE_MOTION_NS");

    if (not switchprop) return;
    if (d == NORTH) switchdir = IUFindSwitch(switchprop, "MOTION_NORTH");
    if (d == SOUTH) switchdir = IUFindSwitch(switchprop, "MOTION_SOUTH");
    if (not switchdir) return;
  }
  if ((d == EAST) || (d==WEST)) {  
    switchprop=telescope->getSwitch("TELESCOPE_MOTION_WE");
 
    if (not switchprop) return;
    if (d == EAST) switchdir = IUFindSwitch(switchprop, "MOTION_EAST");
    if (d == WEST) switchdir = IUFindSwitch(switchprop, "MOTION_WEST");
    if (not switchdir) return;
  }
      
  if (switchprop) {
    IUResetSwitch(switchprop);
    switchdir->s = ISS_ON; 
    client->sendNewSwitch(switchprop);
  }
  
  //printf("Press direction %d\n", d);
}
  
void Pad::changespeed(int speedindex)
{
  ISwitchVectorProperty *slewpreset;
    
  if (slewpreset=telescope->getSwitch("SLEWMODE")) {
   IUResetSwitch(slewpreset);
   slewpreset->sp[speedindex + 1].s = ISS_ON;
   client->sendNewSwitch(slewpreset);
   return;
  }
  changespeed(presetspeedslabels->at(speedindex));
}

void Pad::changespeed(QString speedtext)
{
  INumberVectorProperty *motionrate;
    
  if (motionrate=telescope->getNumber("SLEWSPEEDS")) {
    INumber *raslew=IUFindNumber(motionrate, "RASLEW");
    INumber *deslew=IUFindNumber(motionrate, "DESLEW");
    raslew->value=speedtext.toDouble();
    deslew->value=speedtext.toDouble();
    client->sendNewNumber(motionrate);
    return;
  }
  if (motionrate=telescope->getNumber("TELESCOPE_MOTION_RATE")) {
    INumber *rate=IUFindNumber(motionrate, "MOTION_RATE");
    double speed = speedtext.toDouble();
    double siderealday= 86164.09053;
    speed = (speed * (360 * 60)) / siderealday;
    rate->value = speed;
    client->sendNewNumber(motionrate);
    return;
  }  
  
}

void Pad::setSpeedIndex(int index)
{
  ui->comboBoxspeed->setCurrentIndex(index - 1);
}

void Pad::incspeed(int value)
{
  if (value == 1) {
    if (ui->comboBoxspeed->currentIndex() < (ui->comboBoxspeed->count() -1)) {
      ui->comboBoxspeed->setCurrentIndex(ui->comboBoxspeed->currentIndex() + 1);
      if (telescope) changespeed(ui->comboBoxspeed->currentIndex());
    }
  }
}
void Pad::decspeed(int value)
{
  if (value == 1) {
    if (ui->comboBoxspeed->currentIndex() > 0) {
      ui->comboBoxspeed->setCurrentIndex(ui->comboBoxspeed->currentIndex() - 1);
      if (telescope) changespeed(ui->comboBoxspeed->currentIndex());
    }
  }
}

void Pad::abortmotion()
{
  ISwitchVectorProperty *abortprop=NULL;
  ISwitch *switchabortmotion=NULL;
  if (not telescope || not client) return;
  if (abortprop = telescope->getSwitch("TELESCOPE_ABORT_MOTION")) {
    IUResetSwitch(abortprop);
    //switchabortmotion=IUFindSwitch(abortprop, "ABORT_MOTION");
    switchabortmotion=IUFindSwitch(abortprop, "ABORT");
    switchabortmotion->s = ISS_ON;
    client->sendNewSwitch(abortprop);
  }
}

void Pad::syncLast()
{
  double tra;
  double tdec;
  if (gotos.empty()) return;
  if (not telescope || not client) return;
  coord_t lasttarget = gotos.first();
  
  ISwitchVectorProperty *on_coord_set=telescope->getSwitch("ON_COORD_SET");
  IUResetSwitch(on_coord_set);
  ISwitch *switchsync=IUFindSwitch(on_coord_set, "SYNC");
  switchsync->s=ISS_ON;
  client->sendNewSwitch(on_coord_set);
  INumberVectorProperty *eqcoords=telescope->getNumber("EQUATORIAL_EOD_COORD");
  INumber *ranumber=IUFindNumber(eqcoords, "RA");
  tra = ranumber->value;
  ranumber->value = lasttarget.ra;
  INumber *decnumber=IUFindNumber(eqcoords, "DEC");
  tdec = decnumber->value;
  decnumber->value = lasttarget.dec;
  client->sendNewNumber(eqcoords);  
  
  emit lastgotosynced(tra, tdec);
}

void Pad::addGoto(double ra, double dec)
{
  coord_t s;
  s.ra = ra; s.dec = dec;
  gotos.insert(0, s);
}


QHash<QString,  PadButtonEvent* > Pad::getPadButtonEvents()
{
  return padbuttonevents;
}

PadButtonEvent::PadButtonEvent(Pad *p,QString labl, QPushButton* buttn): QObject()
{
  pad = p;
  label = labl;
  button=buttn;
}

PadButtonEvent::PadButtonEvent(Pad *p, QString labl, PadFn callback): QObject()
{
  pad = p;
  label=labl;
  button=0;
  padcallbacks.insert(labl, callback);
}


QString PadButtonEvent::getLabel()
{
  return label;
}

QPushButton* PadButtonEvent::getButton()
{
  return button;
}

void PadButtonEvent::activate(int value)
{
  if (not pad->getJoypadActive()) return;
  if (button) {
    QMouseEvent event((value) ? QEvent::MouseButtonPress : QEvent::MouseButtonRelease, QPoint(0,0), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier);  
    QApplication::sendEvent(button, &event);  
    return;
  }
  if (padcallbacks[label]) {
    CALL_MEMBER_FN(*pad, padcallbacks[label]) (value);
  }
  
}

